package main

import (
	"demo/flutter_server/application/models"
	"demo/flutter_server/common/config"
	"demo/flutter_server/common/utils"
	"fmt"
	"runtime/debug"
	"strings"
	"time"

	"github.com/goccy/go-json"
	"github.com/gofiber/fiber/v2"
	"github.com/rs/zerolog/log"
)

func main() {
	config.InitZeroLog()
	dependencyInjection()

	app := fiber.New(fiber.Config{
		AppName:     "Flutter Server Demo",
		BodyLimit:   10 * 1024 * 1024,	// 10MB
		IdleTimeout: 30 * time.Second,
		ReadTimeout: 700 * time.Millisecond,
		JSONEncoder: utils.JSONMarshal,
		JSONDecoder: json.Unmarshal,
		StreamRequestBody: false,
	})
	router(app)
	app.Listen(":8080")
}

func router(app *fiber.App) {
	app.Use(apiFilter)
	app.Get("/", func(c *fiber.Ctx) error {
		return c.SendString("Hello, Flutter 👋!")
	})

	app.Post("/login", recoverHandler(authController.Login))
	app.Post("/log", recoverHandler(logController.Log))
	app.Post("/user/refresh_token", recoverHandler(authController.RefreshToken))
	app.Get("/catalog", recoverHandler(catalogController.GetCatalog))
}

func recoverHandler(handler fiber.Handler) fiber.Handler {
	return func(c *fiber.Ctx) error {
		defer func() {
			if r := recover(); r != nil {
				errMsg := fmt.Sprintf("panic: %s", debug.Stack())
				log.Error().Msg(errMsg)
				_ = c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
			}
		}()
		return handler(c)
	}
}

func apiFilter(c *fiber.Ctx) error {
	requestTime := time.Now()
	requestUrl := fmt.Sprintf("%s%s", c.BaseURL(), c.OriginalURL())
	clientIP := utils.GetRequestIp(c)
	log.Info().Msgf("%s, [%s], action: %s", requestTime.Format("2006-01-02 15:04:05"), clientIP, requestUrl)

	actionName := c.Path()
	needAuth := strings.HasPrefix(actionName, "/user/")
	if (needAuth) {
		token := c.Get("Authorization")
		if token == "" {
			return c.JSON(models.Response{
				Code:    models.ResponseAuthError,
				Message: "token error",
			})
		}
		// remove Bearer
		token = token[7:]
		if err := authorizationService.ValidateToken(token); err != nil {
			log.Warn().Err(err).Msgf("refresh token error %v", err)
			return c.JSON(models.Response{
				Code:    models.ResponseAuthError,
				Message: "token error",
			})
		}
	}

	return c.Next()
}